﻿using Microsoft.AspNetCore.SignalR;
using Warehouse.API.Read.HubClients;
using Warehouse.API.Read.HubService;

namespace Warehouse.API.Read.Hubs
{
    /// <summary>
    /// 实时通信集线器 - SignalR Hub 实现类
    /// 负责管理客户端连接、处理实时消息、实现双向通信
    /// 继承自 Hub&lt;IChatClient&gt;，提供强类型的客户端调用接口
    /// </summary>
    public class ChatHub : Hub<IChatClient>
    {
        #region 私有字段

        /// <summary>
        /// 日志记录器 - 用于记录连接状态、错误信息等
        /// </summary>
        private readonly ILogger<ChatHub> _logger;

        /// <summary>
        /// 业务服务 - 处理具体的业务逻辑和数据查询
        /// </summary>
        private readonly CommonService _commonService;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数 - 依赖注入初始化
        /// </summary>
        /// <param name="logger">日志记录器实例</param>
        /// <param name="commonService">业务服务实例</param>
        public ChatHub(ILogger<ChatHub> logger, CommonService commonService)
        {
            _logger = logger;
            _commonService = commonService;
        }

        #endregion

        #region 连接生命周期事件

        /// <summary>
        /// 客户端连接事件 - 当客户端建立 WebSocket 连接时触发
        /// 在此方法中可以执行用户认证、权限验证、连接统计等操作
        /// </summary>
        /// <returns>异步任务</returns>
        public override async Task OnConnectedAsync()
        {
            // 获取连接的唯一标识符
            var connectionId = Context.ConnectionId;
            
            // 获取客户端信息（可选）
            var userAgent = Context.GetHttpContext()?.Request.Headers["User-Agent"].ToString();
            var clientIp = Context.GetHttpContext()?.Connection.RemoteIpAddress?.ToString();

            // 记录连接成功日志
            _logger.LogInformation(
                "客户端连接成功 - ConnectionId: {ConnectionId}, UserAgent: {UserAgent}, IP: {ClientIp}, 时间: {Timestamp}",
                connectionId, userAgent, clientIp, DateTime.Now);

            // 可以在这里实现以下功能：
            // 1. 用户组管理 - 将用户加入特定组
            // 2. 权限验证 - 检查用户是否有权限连接
            // 3. 连接统计 - 记录在线用户数量
            // 4. 发送欢迎消息 - 向新连接的客户端发送欢迎信息

            // 调用基类方法，完成连接建立
            await base.OnConnectedAsync();
        }

        /// <summary>
        /// 客户端断开连接事件 - 当客户端断开 WebSocket 连接时触发
        /// 在此方法中可以执行清理工作、更新统计信息等操作
        /// </summary>
        /// <param name="exception">断开连接的原因，如果正常断开则为 null</param>
        /// <returns>异步任务</returns>
        public override async Task OnDisconnectedAsync(Exception? exception)
        {
            // 获取连接的唯一标识符
            var connectionId = Context.ConnectionId;

            // 根据是否有异常记录不同级别的日志
            if (exception != null)
            {
                // 异常断开 - 记录警告日志
                _logger.LogWarning(exception,
                    "客户端异常断开 - ConnectionId: {ConnectionId}, 异常信息: {ExceptionMessage}, 时间: {Timestamp}",
                    connectionId, exception.Message, DateTime.Now);
            }
            else
            {
                // 正常断开 - 记录信息日志
                _logger.LogInformation(
                    "客户端正常断开 - ConnectionId: {ConnectionId}, 时间: {Timestamp}",
                    connectionId, DateTime.Now);
            }

            // 可以在这里实现以下功能：
            // 1. 清理用户状态 - 移除用户相关的缓存数据
            // 2. 更新统计信息 - 减少在线用户计数
            // 3. 通知其他用户 - 告知用户离线状态
            // 4. 保存用户会话 - 保存用户的操作历史

            // 调用基类方法，完成断开连接处理
            await base.OnDisconnectedAsync(exception);
        }

        #endregion

        #region 业务方法

        /// <summary>
        /// 处理实时查询请求 - 客户端调用的核心业务方法
        /// 实现库存数据的实时查询和推送功能
        /// 采用 CQRS 模式，通过 MediatR 处理查询请求
        /// </summary>
        /// <param name="user">用户标识 - 用于日志记录和权限验证</param>
        /// <param name="message">查询条件 - 产品名称，支持模糊查询</param>
        /// <returns>异步任务</returns>
        public async Task SendMessage(string user, string message)
        {
            try
            {
                // 记录请求日志
                _logger.LogInformation(
                    "收到实时查询请求 - 用户: {User}, 产品名称: {ProductName}, ConnectionId: {ConnectionId}, 时间: {Timestamp}",
                    user, message, Context.ConnectionId, DateTime.Now);

                // 构建查询命令对象 - 使用 CQRS 模式
                var queryCommand = new Warehouse.API.Read.App.Commands.ReportSummary
                {
                    pageindex = 1,           // 页码：固定为第一页
                    pagesize = 10,           // 页大小：固定为 10 条记录
                    ProductName = message    // 查询条件：产品名称
                };

                // 通过业务服务执行查询 - 使用 MediatR 模式
                // 这会自动路由到对应的 Handler 进行处理
                var queryResult = await _commonService.SendMessage(queryCommand);

                // 广播查询结果 - 推送给所有连接的客户端
                // 使用强类型接口，确保类型安全
                await Clients.All.SendMessage(queryResult);

                // 记录成功日志
                _logger.LogInformation(
                    "实时查询完成 - 用户: {User}, 产品名称: {ProductName}, 返回记录数: {RecordCount}, 时间: {Timestamp}",
                    user, message, queryResult.Data?.Data?.Count ?? 0, DateTime.Now);
            }
            catch (Exception ex)
            {
                // 异常处理 - 记录错误日志
                _logger.LogError(ex,
                    "实时查询失败 - 用户: {User}, 产品名称: {ProductName}, 错误信息: {ErrorMessage}, 时间: {Timestamp}",
                    user, message, ex.Message, DateTime.Now);

                // 向调用方发送错误信息
                await Clients.Caller.SendMessage(new
                {
                    code = 500,
                    message = "查询失败，请稍后重试",
                    data = (object?)null,
                    timestamp = DateTime.Now
                });
            }
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 获取当前连接信息 - 用于调试和监控
        /// </summary>
        /// <returns>连接信息对象</returns>
        private object GetConnectionInfo()
        {
            return new
            {
                ConnectionId = Context.ConnectionId,
                UserAgent = Context.GetHttpContext()?.Request.Headers["User-Agent"].ToString(),
                ClientIp = Context.GetHttpContext()?.Connection.RemoteIpAddress?.ToString(),
                ConnectedAt = DateTime.Now
            };
        }

        #endregion
    }
}
